package me.jzn.alib.utils;

import android.util.Xml;

import androidx.annotation.RawRes;
import androidx.annotation.XmlRes;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import me.jzn.alib.ALib;
import me.jzn.core.Core;
import me.jzn.core.exceptions.ShouldNotRunHereException;
import me.jzn.core.utils.StrUtil;
import me.jzn.core.vm.VmConst;

public class XmlXppUtil {
    private static final Logger log = LoggerFactory.getLogger(XmlXppUtil.class);

    public static XmlPullParser parseRaw(@RawRes int rawRes) {
        XmlPullParser xpp = Xml.newPullParser();
        try {
            xpp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
            xpp.setInput(ResUtil.getRaw(rawRes), StrUtil.UTF8);
            return xpp;
        } catch (XmlPullParserException e) {
            throw new ShouldNotRunHereException(e);
        }
    }

    public static XmlPullParser parseXml(@XmlRes int xmlRes) {
        return ALib.app().getResources().getXml(xmlRes);
    }

    public static String getAttributeValue(XmlPullParser pp, String name) {
        if (VmConst.isAndroid) {
            // android 只能是空才能取出正确属性
            return pp.getAttributeValue(null, name);
        }
        return pp.getAttributeValue(XmlPullParser.NO_NAMESPACE, name);
    }

    /**
     * Skip sub tree that is currently porser positioned on.
     * <br>NOTE: parser must be on START_TAG and when funtion returns
     * parser will be positioned on corresponding END_TAG
     */
    public static void skipSubTree(XmlPullParser pp) {
        try {
            pp.require(XmlPullParser.START_TAG, null, null);
            int level = 1;
            while (level > 0) {
                int eventType = pp.next();
                if (eventType == XmlPullParser.END_TAG) {
                    --level;
                } else if (eventType == XmlPullParser.START_TAG) {
                    ++level;
                }
            }
        } catch (XmlPullParserException | IOException e) {
            throw new ShouldNotRunHereException(e);
        }
    }

    public static void nextTag(XmlPullParser xpp, boolean isStart) {
        try {
            int event = xpp.getEventType();
            while (event != XmlPullParser.END_DOCUMENT) {
                xpp.next();
                event = xpp.getEventType();
                if (isStart && event == XmlPullParser.START_TAG) {
                    return;
                } else if (!isStart && event == XmlPullParser.END_TAG) {
                    return;
                }
            }
        } catch (XmlPullParserException | IOException e) {
            throw new ShouldNotRunHereException(e);
        }
    }

    public static final void nextTag(XmlPullParser xpp, boolean isStart, String tagName) {
        try {
            int event = xpp.getEventType();
            while (event != XmlPullParser.END_DOCUMENT) {
                xpp.next();
                event = xpp.getEventType();
                boolean isValid = (isStart && event == XmlPullParser.START_TAG) || (!isStart && event == XmlPullParser.END_TAG);
                if (isValid && tagName.equals(xpp.getName())) {
                    return;
                }
            }
        } catch (XmlPullParserException | IOException e) {
            throw new ShouldNotRunHereException(e);
        }
    }

    /**
     * 你得确定子对象是text才能调用
     */
    public static final String getText(XmlPullParser xpp) {
        String tag = xpp.getName();
        try {
            xpp.next();
            if (xpp.getEventType() != XmlPullParser.TEXT) {
                throw new IllegalStateException("not TEXT for " + tag);
            }
            String text = xpp.getText();
            xpp.next();
            if (Core.isDebug() && xpp.getEventType() != XmlPullParser.END_TAG) {
                throw new IllegalStateException("not END after text for " + tag);
            }
            return text;
        } catch (XmlPullParserException | IOException e) {
            throw new ShouldNotRunHereException(e);
        }
    }

    public static String debugXppStatus(XmlPullParser xpp) {
        int event = -1;
        try {
            event = xpp.getEventType();
        } catch (XmlPullParserException e) {
            throw new ShouldNotRunHereException(e);
        }
        String tag = xpp.getName();
        String xns = xpp.getNamespace();
        if (xns != null && xns.length() > 0) {
            tag = xns + ":" + tag;
        }
        switch (event) {
            case XmlPullParser.START_TAG:
                return String.format("<%s>", tag);
            case XmlPullParser.END_TAG:
                return String.format("</%s>", tag);
            case XmlPullParser.START_DOCUMENT:
                return "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
            case XmlPullParser.END_DOCUMENT:
                return "EOF";
            case XmlPullParser.TEXT:
                String text = StrUtil.trim(xpp.getText());
                if (text == null) {
                    return "SPACE";
                }
                return text;
            case XmlPullParser.COMMENT:
                return "<!-- -->";
            default:
                return "unkown event:" + event;
        }
    }

    /**
     * 当前必须在父节点.结束的时候，在父节点的END
     */
    public static void visitChildrenTag(XmlPullParser xpp, Runnable action) {
        int depth = xpp.getDepth();
        int nextDepth = depth + 1;
        try {
            int event = xpp.getEventType();
            while (event != XmlPullParser.END_DOCUMENT) {
                xpp.next();
                event = xpp.getEventType();
                if (event == XmlPullParser.START_TAG && xpp.getDepth() == nextDepth) {
                    action.run();
                } else if (event == XmlPullParser.END_TAG && xpp.getDepth() == depth) {
                    break;
                }
            }
        } catch (IOException | XmlPullParserException e) {
            if (Core.isDebug()) {
                throw new ShouldNotRunHereException(e);
            } else {
                ALib.log().error("xml error!", e);
            }
        }
    }

    /**
     * <list>
     * <item>aaa</item>
     * <item>bbb</item>
     * </list>
     * 获取aaa/bbb这样的
     */
    public static List<String> getListTexts(XmlPullParser xpp) {
        List<String> list = new ArrayList<>();
        try {
            int event = xpp.getEventType();
            if (Core.isDebug() && !"list".equals(xpp.getName()) || event != XmlPullParser.START_TAG) {
                throw new IllegalStateException("must be <list>");
            }

            int depth = xpp.getDepth();
            int nextDepth = depth + 1;

            while (event != XmlPullParser.END_DOCUMENT) {
                xpp.next();
                event = xpp.getEventType();
                if (event == XmlPullParser.TEXT && xpp.getDepth() == nextDepth) {
                    list.add(xpp.getText());
                } else if (event == XmlPullParser.END_TAG && xpp.getDepth() == depth) {
                    break;
                }
            }
        } catch (IOException | XmlPullParserException e) {
            if (Core.isDebug()) {
                throw new ShouldNotRunHereException(e);
            } else {
                ALib.log().error("xml error!", e);
            }
        }
        return list;

    }
}
